home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-07-03 | 17.6 KB | 540 lines | [TEXT/MPS ] |
- (*[n+,u+,r+,d+,#+,j=13-/40/1o,t=2,o=95] PasMat formatting options*)
-
- (*------------------------------------------------------------------------------
-
- FILE ResEqual.p
- Copyright Apple Computer, Inc. 1986, 1987
- All rights reserved.
-
- NAME
- ResEqual -- compare resources in two files
-
- SYNOPSIS
- resequal [-p] file1 file2
-
- DESCRIPTION
- "resequal" compares the resources in two files. If both files contain
- the same resources, and all of the resources are equal, it runs silently.
- It reports resources found in only one of the files, resources of
- different sizes, resources with different contents, and differing
- resource attributes. Output is written to standard output. The -p
- option writes progress information to diagnostic output.
- ------------------------------------------------------------------------------*)
- (*$R-*) (* Turn off range checking*)
- MODULE ResEqual;
-
- IMPORT SYSTEM, Types, Resources, Memory, Files, DWrite, Write, CursorCtl,
- IntEnv, Signal, SegLoad, PasLibIntf, Strings;
-
- (* CONST
- Version = '2.1'; Current version, now in 'vers' resource*)
- CONST
- RC_Normal=0; RC_ParmErrs=1; RC_DontMatch=2; (*RC_Abort=3;*)
- VAR
- file1Ref: INTEGER; (* the refnums for our files *)
- file2Ref: INTEGER;
- curRes: INTEGER;
- file1Name: Types.Str255; (* the names of the files we're comparing*)
- file2Name: Types.Str255;
- quiet: BOOLEAN; (* True ==> no info on Diagnostic file*)
- progName: Types.Str255; (* Program's file name*)
- interrupted: BOOLEAN; (* True ==> interrupted (Cmd "." pressed)*)
- retCode: INTEGER; (*Return codes*)
- (*$J+ external variables*)
- OUTPUT: LONGINT; (* standard output *)
- (*$J- external variables*)
-
- (*[j=0] PasMat formatting option*)
-
- (**----------------------------------*
- | Stop - terminate execution |
- *----------------------------------**)
-
- PROCEDURE Stop(msg: ARRAY OF CHAR);
-
- BEGIN (*Stop*)
- IF msg[0]#0X THEN
- PasLibIntf.PLFlush(OUTPUT);
- DWrite.Ln;
- DWrite.String(msg);
- DWrite.Ln
- END;
-
- IF interrupted THEN HALT(-9) END;
- (* don't worry about closing the files we opened. The Shell
- will do so if appropriate.*)
- HALT(retCode); (*exit, returning the appropriate status code*)
- END Stop; (*Stop*)
-
- (**--------------------------------------*
- | Intr - Process external interrupt |
- | this routine is passed to IEsigset |
- *--------------------------------------**)
-
- (*$Calling Pascal*)
- PROCEDURE Intr;
- BEGIN
- interrupted := TRUE; (*we test this switch periodically*)
- END Intr;
- (*$Calling Oberon*)
-
- (*$S Init*)
-
- (**-------------------------------------------------------------*
- | SyntaxError - Report an error in parameters or options |
- *-------------------------------------------------------------**)
-
- PROCEDURE SyntaxError(suffix: ARRAY OF CHAR);
- VAR msg: ARRAY 256 OF CHAR;
- BEGIN (*SyntaxError*)
- PasLibIntf.PLFlush(OUTPUT);
- DWrite.String('### ');
- DWrite.String(progName);
- DWrite.String(' - ');
- DWrite.String(suffix);
- DWrite.Ln;
- COPY("# Usage: ", msg); APPEND(progName, msg);
- APPEND(" file1 file2 [-p]", msg);
- Stop(msg);
- END SyntaxError; (*SyntaxError*)
-
- (**-----------------------------------*
- | LetterOpt - Set a letter option |
- *-----------------------------------**)
-
- PROCEDURE LetterOpt(opt: CHAR; (*VAR*) argVIndex: INTEGER);
- (* note only one option is supported. argVIndex is passed to
- this routine so options that have arguments can 'eat' them*)
- VAR msg: ARRAY 256 OF CHAR;
- BEGIN
- IF (opt='p') OR (opt='P') THEN
- quiet := FALSE
- ELSE
- COPY(IntEnv.ArgV[argVIndex]^, msg);
- APPEND(" <invalid option>", msg);
- SyntaxError(msg);
- END
- END LetterOpt;
-
- (**---------------------------*
- | Init - Tool initalization |
- *---------------------------**)
-
- PROCEDURE Init;
-
- VAR
- argVIndex, fileCount, holdIndex, i: INTEGER;
- prevSig: Signal.SignalHandler;
- versH: Files.VersRecHndl;
- arg: Types.Str255;
- versStr: Types.Str255;
-
- BEGIN
- retCode := RC_Normal;
-
- interrupted := FALSE; (*becomes True when interrupted*)
- prevSig := Signal.IEsignal(Signal.SIGINT, Intr);
-
- quiet := TRUE;
- COPY(IntEnv.ArgV[0]^, progName);
- retCode := RC_ParmErrs;
-
- fileCount := 0;
- retCode := RC_ParmErrs;
- file1Ref := - 1; (* so we tell if the open works*)
- file2Ref := - 1; (* as above*)
- argVIndex := 1;
- WHILE argVIndex < IntEnv.ArgC DO (*ArgC is the number of args plus one*)
- COPY(IntEnv.ArgV[argVIndex]^, arg);
- IF arg[0] # 0X THEN
- IF arg[1] = '-' THEN (* we have an option *)
- holdIndex := argVIndex;
- LetterOpt(arg[2], argVIndex);
- IF argVIndex # holdIndex THEN DEC(argVIndex) END; (* skip the increment of argVIndex below*)
- ELSE (* it must be a file to open*)
- INC(fileCount);
- IF fileCount = 1 THEN
- COPY(IntEnv.ArgV[argVIndex]^, file1Name)
- ELSE
- COPY(IntEnv.ArgV[argVIndex]^, file2Name)
- END;
- END;
- END;
- INC(argVIndex)
- END;
- IF fileCount # 2 THEN SyntaxError('Invalid Parameters') END;
- curRes := Resources.CurResFile();
-
- IF ¬quiet THEN
- DWrite.Ln;
-
- versH := Files.VersRecHndl(Resources.Get1Resource(LONG("vers"), 1)); (*get the version from the 'vers' resource*)
-
- IF versH # NIL THEN
- i:=1;
- WHILE i<=ORD(versH.shortVersion[0]) DO
- versStr[i-1]:=versH.shortVersion[i]; INC(i)
- END;
- versStr[i]:=0X;
- Resources.ReleaseResource(Types.Handle(versH));
- COPY(progName, arg); APPEND(" (Ver ", arg);
- APPEND(versStr, arg); APPEND(")", arg);
- DWrite.String(arg)
- ELSE
- COPY(progName, arg); APPEND(" (Ver **unavailable**)", arg);
- DWrite.String(arg)
- END;
-
- DWrite.Ln;
- DWrite.Ln;
- DWrite.Ln
- END;
-
- Resources.SetResLoad(FALSE); (* keep preloads from loading*)
- versStr:=file2Name; Strings.C2PStrProc(SYSTEM.ADR(versStr));
- file2Ref := Resources.OpenRFPerm(versStr, 0, Files.fsRdPerm);
- Resources.SetResLoad(TRUE);
- IF file2Ref = - 1 THEN
- COPY("### ", arg); APPEND(progName, arg);
- APPEND(" - ", arg); APPEND("could not open ", arg);
- APPEND(file2Name, arg);
- Stop(arg)
- END;
- Resources.SetResLoad(FALSE); (* keep preloads from loading*)
- versStr:=file1Name; Strings.C2PStrProc(SYSTEM.ADR(versStr));
- file1Ref := Resources.OpenRFPerm(versStr, 0, Files.fsRdPerm);
- Resources.SetResLoad(TRUE);
- Resources.UseResFile(curRes); (* in case file2 opened, but file one doesn't*)
- IF file1Ref = - 1 THEN
- COPY("### ", arg); APPEND(progName, arg);
- APPEND(" - ", arg); APPEND("could not open ", arg);
- APPEND(file1Name, arg);
- Stop(arg)
- END;
-
- retCode := RC_Normal;
-
- CursorCtl.RotateCursor(0);
- IF interrupted THEN Stop("") END;
- END Init;
-
- (*$S Main*)
-
- (**-------------------------------------------------*
- | ByteToStr - Convert a byte to a hex string |
- *-------------------------------------------------**)
-
- PROCEDURE ByteToStr(N: INTEGER; VAR s: ARRAY OF CHAR);
- VAR d: INTEGER;
- BEGIN
- IF N = 0 THEN
- COPY("00", s);
- ELSE
- s[2]:=0X; d:=BAND(ASH(N, -4), $F)+ORD("0");
- IF d>ORD("9") THEN INC(d, ORD("A")-ORD("9")-1) END;
- s[0]:=CHR(d); d:=BAND(N, $F)+ORD("0");
- IF d>ORD("9") THEN INC(d, ORD("A")-ORD("9")-1) END;
- s[1]:=CHR(d)
- END
- END ByteToStr;
-
- PROCEDURE DumpMem(firstStart, secondStart: Types.Ptr; offset, size: LONGINT);
-
- PROCEDURE DumpPtr(theStart: Types.Ptr);
-
- VAR
- count, len: INTEGER;
- limit: LONGINT;
- thePtr: Types.Ptr;
- theStr, byte: Types.Str255;
- b: Types.SignedByte;
-
- BEGIN
- limit := size - offset;
- IF limit > 16 THEN limit := 16 END;
- theStr := "";
- thePtr := theStart;
- FOR count := 1 TO SHORT(limit) DO
- SYSTEM.GET(LONGINT(thePtr), b); ByteToStr(b, byte);
- APPEND(byte, theStr); APPEND(" ", theStr);
- thePtr := Types.Ptr(LONGINT(thePtr) + 1)
- END;
- APPEND(' ', theStr);
- thePtr := theStart;
- len := LENGTH(theStr) + SHORT(limit);
- theStr[len] := 0X;
- FOR count := len - SHORT(limit) + 1 TO len DO
- SYSTEM.GET(LONGINT(thePtr), b);
- IF (ORD(' ')<=b) & (b<=ORD('z')) THEN
- theStr[count] := CHR(b)
- ELSE
- theStr[count] := '.'
- END;
- thePtr := Types.Ptr(LONGINT(thePtr) + 1)
- END;
- Write.String(theStr); Write.Ln
- END DumpPtr;
-
- BEGIN
- Write.String("Contents of resource in file 1 at offset ");
- Write.Int(offset, 1); Write.Ln;
- DumpPtr(firstStart);
- Write.String("Contents of resource in file 2 at offset ");
- Write.Int(offset, 1); Write.Ln;
- DumpPtr(secondStart);
- Write.Ln;
- END DumpMem;
-
- (**--------------------------------------*
- | DoIt -- check resources in each file |
- *--------------------------------------**)
-
- PROCEDURE DoIt; (* the guts of our program--in a procedure so the
- compiler can do register optimizations*)
-
- VAR
- cursorCount: INTEGER; (* for our spinning cursor*)
-
- theType: Types.ResType; (* parameters for GetResInfo calls*)
- theID: INTEGER;
- theName: Types.Str255;
-
- theSize1, theSize2: LONGINT;
- theAttr1, theAttr2: INTEGER;
-
- (**-------------------------------------------*
- | CheckResources -- compare those resources |
- *-------------------------------------------**)
-
- PROCEDURE CheckResources;
-
- VAR
- typeIndex, resIndex: INTEGER; (* counters for our getindXXXX calls*)
-
- theRes1, theRes2: Types.Handle; (* handles for our resource compares*)
- clearRes1, clearRes2: BOOLEAN; (* call emptyhandle if True*)
- firstTime: BOOLEAN; (* have we written anything yet?*)
- res1State, res2State: Types.SignedByte; (* to save and restore MP flags*)
-
- PROCEDURE TellIt(message: ARRAY OF CHAR);
-
- BEGIN
- IF firstTime THEN
- Write.Ln;
- Write.String("File #1: "); Write.String(file1Name); Write.Ln;
- Write.String("File #2: "); Write.String(file2Name); Write.Ln;
- Write.Ln;
- firstTime := FALSE;
- retCode := RC_DontMatch;
- END;
- Write.String(message); Write.Ln;
- Write.String("Resource Type = \034");
- Write.OSType(theType);
- Write.String("\034 ID = ");
- Write.Int(theID, 1);
- Write.Ln
- END TellIt;
-
- PROCEDURE TellAttr(theAttr: INTEGER);
-
- (* These constants are found in the Resource Manager chapter of
- Inside Macintosh Vol I, page 111. Only bits 1-6 of the low-order
- byte of the INTEGER are used for flags. The other bits of the
- INTEGER are reserved or ignored. *)
- BEGIN
- IF BAND(theAttr, $2) # 0 THEN Write.String('changed ') END;
- IF BAND(theAttr, $4) # 0 THEN Write.String('preload ') END;
- IF BAND(theAttr, $8) # 0 THEN Write.String('protected ') END;
- IF BAND(theAttr, $10) # 0 THEN Write.String('locked ') END;
- IF BAND(theAttr, $20) # 0 THEN Write.String('purgable ') END;
- IF BAND(theAttr, $40) # 0 THEN Write.String('sysHeap ') END;
- IF BAND(theAttr, $7E) = 0 THEN Write.String('-No flags set-') END;
- Write.Ln;
- END TellAttr;
-
- (**-------------------------------------------------*
- | CheckEqual--compares contents of 2 handles |
- *-------------------------------------------------**)
-
- PROCEDURE CheckEqual(a, b: Types.Handle; size: LONGINT);
-
- CONST
- maxBad = 10;
-
- VAR
- count: LONGINT;
- srcB, trgB: Types.SignedByte;
- source, target: Types.Ptr;
- numBad: INTEGER;
-
- BEGIN
- numBad := 0; (* no problems so far*)
- source := MASTERPTR(a);
- target := MASTERPTR(b);
- count := 0;
- WHILE count < size DO
- SYSTEM.GET(LONGINT(source), srcB);
- SYSTEM.GET(LONGINT(target), trgB);
- IF srcB # trgB THEN
- IF numBad = 0 THEN TellIt('Resources have different contents') END;
- DumpMem(source, target, count, size);
- numBad := numBad + 1;
- IF numBad >= maxBad THEN RETURN END;
- source := Types.Ptr(LONGINT(source) + 16);
- target := Types.Ptr(LONGINT(target) + 16);
- count := count + 16;
- ELSE
- source := Types.Ptr(LONGINT(source) + 1);
- target := Types.Ptr(LONGINT(target) + 1);
- count := count + 1;
- END;
- END;
- END CheckEqual;
-
- BEGIN
- firstTime := TRUE;
- Resources.UseResFile(file1Ref);
- FOR typeIndex := 1 TO Resources.Count1Types() DO (* countTypes counts Types in 1st file*)
- Resources.UseResFile(file1Ref);
- Resources.Get1IndType(theType, typeIndex); (* get the next type*)
- FOR resIndex := 1 TO Resources.Count1Resources(theType) DO
- Resources.UseResFile(file1Ref);
- Resources.SetResLoad(FALSE); (* we want the info, but not the data right now*)
- theRes1 := Resources.Get1IndResource(theType, resIndex);
- Resources.SetResLoad(TRUE); (* so loadseg will really get our segments*)
- Resources.UseResFile(curRes);
-
- cursorCount := cursorCount + 1;
- CursorCtl.RotateCursor(cursorCount);
-
- IF interrupted THEN Stop("") END; (* in case the user hit command-period*)
-
- (* we want the resource ID and name*)
- Resources.GetResInfo(theRes1, theID, theType, theName);
- Resources.UseResFile(file2Ref); (* now we will try to find a match in the other file*)
- Resources.SetResLoad(FALSE); (* we want the info, but not the data right now*)
- theRes2 := Resources.Get1Resource(theType, theID); (* resLoad is FALSE*)
- Resources.SetResLoad(TRUE); (* so loadseg will really get our segments*)
- Resources.UseResFile(curRes); (* from our resource file*)
-
- IF ~quiet THEN
- PasLibIntf.PLFlush(OUTPUT);
- DWrite.String("Checking resource ");
- DWrite.Int(theType, 1);
- DWrite.String(" #");
- DWrite.Int(theID, 1);
- DWrite.Ln
- END;
-
- IF theRes2 = NIL THEN (*not in our file*)
- TellIt('In 1 but not in 2');
- Write.Ln;
-
- ELSE
- theAttr1 := Resources.GetResAttrs(theRes1);
- theAttr2 := Resources.GetResAttrs(theRes2);
- (* Use the $7E constant since only bits 1-6 are significant.*)
- IF BAND(theAttr1, $7E) # BAND(theAttr2, $7E) THEN
- TellIt('Resources have different flags');
- Write.String('Flags 1 = ');
- TellAttr(theAttr1);
- Write.String('Flags 2 = ');
- TellAttr(theAttr2);
- Write.Ln;
- END;
- theSize1 := Resources.SizeResource(theRes1);
- theSize2 := Resources.SizeResource(theRes2);
- IF theSize1 # theSize2 THEN
- TellIt('Resources are different sizes');
- Write.String("Size 1 = ");
- Write.Int(theSize1, 1);
- Write.String(" Size 2 = ");
- Write.Int(theSize2, 1);
- Write.Ln;
- ELSE
- clearRes1 := MASTERPTR(theRes1) = NIL;
- Resources.LoadResource(theRes1); (* resload is TRUE, so get the data--add check for
- reserr*)
- IF Resources.ResError() # 0 THEN
- Stop('Could not load resource');
- END;
- res1State := Memory.HGetState (theRes1); (* save current MP flags*)
- Memory.HNoPurge(theRes1); (* don't let it be purged*)
- clearRes2 := MASTERPTR(theRes2) = NIL;
- Resources.LoadResource(theRes2); (* as above*)
- IF Resources.ResError() # 0 THEN
- Stop('Could not load resource');
- END;
- res2State := Memory.HGetState (theRes2); (* save current MP flags*)
- Memory.MoveHHi(theRes2);
- Memory.HLock(theRes2); (* lock it down*)
- Memory.MoveHHi(theRes1);
- Memory.HLock(theRes1); (* this one as well*)
- CheckEqual(theRes1, theRes2, theSize1);
- Memory.HSetState(theRes1,res1State);
- Memory.HSetState(theRes2,res2State);
- IF clearRes1 THEN Memory.EmptyHandle(theRes1) END; (* free memory if we loaded resource*)
- IF clearRes2 THEN Memory.EmptyHandle(theRes2) END; (* as above*)
- END (*ELSE sizes equal*)
- END; (*ELSE res in both files*)
- END;
- END;
-
- Resources.UseResFile(file2Ref);
- FOR typeIndex := 1 TO Resources.Count1Types() DO (* countTypes counts Types in 2nd file*)
- Resources.UseResFile(file2Ref);
- Resources.Get1IndType(theType, typeIndex); (* get the next type*)
- FOR resIndex := 1 TO Resources.Count1Resources(theType) DO
- Resources.UseResFile(file2Ref);
- Resources.SetResLoad(FALSE); (* we want the info, but not the data right now*)
- theRes2 := Resources.Get1IndResource(theType, resIndex);
- Resources.SetResLoad(TRUE); (* so loadseg will really get our segments*)
- Resources.UseResFile(curRes);
-
- cursorCount := cursorCount + 1;
- CursorCtl.RotateCursor(cursorCount);
-
- IF interrupted THEN Stop('') END; (* in case the user hit command-period*)
-
- (* we want the resource ID and name*)
- Resources.GetResInfo(theRes2, theID, theType, theName);
- Resources.UseResFile(file1Ref); (* now we will try to find a match in the other file*)
- Resources.SetResLoad(FALSE); (* we want the info, but not the data right now*)
- theRes1 := Resources.Get1Resource(theType, theID); (* resLoad is FALSE*)
- Resources.SetResLoad(TRUE); (* so loadseg will really get our segments*)
- Resources.UseResFile(curRes); (* from our resource file*)
-
- IF ¬quiet THEN
- PasLibIntf.PLFlush(OUTPUT);
- DWrite.String("Checking resource ");
- DWrite.Int(theType, 1);
- DWrite.String(" #");
- DWrite.Int(theID, 1);
- DWrite.Ln
- END;
-
- IF theRes1 = NIL THEN (*not in our file*)
- TellIt('In 2 but not in 1');
- Write.Ln;
- END
-
- END;
- END;
- END CheckResources;
-
- BEGIN
- cursorCount := 0; (* prepare to spin that cursor*)
- CheckResources;
- Stop('');
- END DoIt;
-
- (**----------------------------*
- | ResEqual -- main program |
- *----------------------------**)
- (*$MAIN*)
- BEGIN
- Init; (* sets up world, opens our resource files*)
- SegLoad.UnloadSeg(SYSTEM.ADR(Init)); (* release our initialization segment*)
- DoIt; (* and call our routine*)
- END ResEqual.
-